#ifndef _ML_INTERSTREAM_H_
#define _ML_INTERSTREAM_H_
#include "MLCommon.h"
#include "MLDataSet.h"
#include "MLDataVector.h"
#include "MLDataPoint.h"
#include "MLDistanceFunctions.h"
#include "MLDataClustering.h"

using namespace mylablib;

class CMLInterStream;

class CMLInterStreamCluster
{
public:
	// Constructor and Destructor
	CMLInterStreamCluster(CMLInterStream* pStream, int nID);
	~CMLInterStreamCluster(void);

public:
	// Methods
	int  Create(const CMLDataSet& dataSet);
	int  Create(const CMLDataPoint& dataPoint, int nTime);
	int  Absorb(const CMLDataPoint& dataPoint, int nTime);
	int  Popout(int nTimeDeadline);
	int  Reset(void);

public:
	// Events
	bool TriggerDriftEvent(void);
	bool TriggerDieOutEvent(void);
	bool TriggerSplitEvent(void);
	int  ExecuteSplit(CMLInterStreamCluster* pNewCluster);
	int  ExecuteDieOut(void);
	int  ExecuteMerge(CMLInterStreamCluster* pNearCluster);
	int  ExecuteThrowOut(void);

public:
	// Properties
	inline int GetSWLength() const { return (int)m_SlidingWindow.size(); };

	inline bool CanAbsorb(const CMLDataPoint& dataPoint, double rmax)
	{
		int N = GetSWLength();
		CMLDataPoint tmp = ((m_vSS+(dataPoint^2))/N) - (((m_vLS+dataPoint)/N)^2);
		double sum = 0.0;
		for (int i=0;i<tmp.size();i++)
			sum += tmp[i]*m_pDistFunc->GetWeight(i)*m_pDistFunc->GetWeight(i);
		if (sum > rmax*rmax)
			return false;
		else
			return true;
	}

	inline const CMLDataPoint& GetLS() const { return m_vLS; };

	inline const CMLDataPoint& GetSS() const { return m_vSS; };

	inline CMLDataPoint GetCF() const 
	{
		CMLDataPoint cf(m_vLS.size()+m_vSS.size()+1);
		int cfi=0;
		for (int i=0; i<m_vLS.size(); i++)
			cf[cfi++] = m_vLS[i];
		for (int i=0; i<m_vSS.size(); i++)
			cf[cfi++] = m_vSS[i];
		cf[cfi] = GetSWLength();
		return cf;
	}

	inline CMLDataPoint GetAf() const 
	{
		CMLDataPoint center = GetCenter(); 
		CMLDataPoint af(center.size() + 1);

		if (GetSWLength() == 0)
		{
			for (int i=0; i<af.size(); i++)
				af[i] = 0;
		}
		else
		{
			for (int i=0; i<center.size(); i++)
				af[i] = center[i];
			af[center.size()] = GetSWLength();
		}
		return af;
	}

	inline CMLDataPoint GetCenter() const
	{
		return m_vLS / GetSWLength(); 
	}

	inline double GetRadius() const 
	{ 
		int N = GetSWLength();
		CMLDataPoint tmp = (m_vSS/N) - ((m_vLS/N)^2);
		double sum = 0.0;
		for (int i=0;i<tmp.size();i++)
			sum += tmp[i]*m_pDistFunc->GetWeight(i)*m_pDistFunc->GetWeight(i);
		return sqrt(sum);
	}

	inline double GetAvgTime() const
	{
		return m_TimeLS/GetSWLength();
	}

	inline int GetID() const { return m_nID; };

private:
	// Types
	struct SlidingWindowElem_
	{
		CMLDataPoint dataPoint;
		int nTime;
	};

private:
	// Fields
	std::list<SlidingWindowElem_> m_SlidingWindow;
	CMLDataPoint m_vLS;
	CMLDataPoint m_vSS;
	double m_TimeLS;

	CMLInterStream* m_pStream;
	CMLWeightedEuclideanDistance* m_pDistFunc;
	
	int m_nID;
};

class CMLInterStream
{
public:
	// Constructor and Destructor
	CMLInterStream(void);
	~CMLInterStream(void);

public:
	// Interfaces
	int SetParameters(const std::wstring& wstrParams);
	int Insert(const CMLDataPoint& dataPoint, int nTime);

public:
	// Methods
	int MaintainClusters(void);
	int MaintainClusterCount(void);
	int Release(void);

	inline CMLWeightedEuclideanDistance* GetDistanceFunc() const { return m_pDistFunc; };

private:
	// Inner Types

public:
	// Properties
	inline void SetDistanceWeights(const CMLDataPoint& weights) { m_pDistFunc->SetWeights(weights); };
	inline void SetNumInitClusters(int nNum)     { m_nNumInitClusters = nNum; };
	inline int  GetNumClusters(void) const    { return (int)m_vpClusters.size(); };
	inline void SetInitNumber(int nNum)       { m_nInitNumber = nNum; };
	inline int  GetInitNumber(void) const     { return m_nInitNumber; };
	inline void SetMaxNumClusters(int nMax)   { m_nNumMaxClusters = nMax; };
	inline void SetMinNumClusters(int nMin)   { m_nNumMinClusters = nMin; };
	
	inline void SetMaxRadius(double max) { m_dMaxRadius = max; };
	inline double GetMaxRadius(void) const { return m_dMaxRadius; };

	inline int  GetTotalPointNumber(void) const { return m_nDataPointTotalNumber; };
	inline std::vector<CMLInterStreamCluster*>& GetClusters(void) { return m_vpClusters; };
	inline void SetTimeHorizon(int nLen) { m_nTimeHorizon = nLen; };
	inline int  GetTimeHorizon(void) const { return m_nTimeHorizon; };
	inline int  GetTimeNow() { return m_nTimeNow; };

private:
	// Implementations
	int CreateClusters(void);
	int FindNearestCluster(const CMLDataPoint& point);
	int GrowNewCluster(void);
	
protected:
	// Fields
	CMLWeightedEuclideanDistance* m_pDistFunc;

private:
	// Fields
	std::vector<CMLInterStreamCluster*> m_vpClusters;
	CMLDataSet m_DataSet;
	int        m_nNumInitClusters;
	int        m_nNumMaxClusters;
	int        m_nNumMinClusters;
	int        m_nTimeHorizon;

	int        m_nInitNumber;
	int        m_nDataPointTotalNumber;
	double     m_dMaxRadius;
	int        m_nTimeNow;
	int        m_nClusterIdCounter;
};


#endif
